// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/type/tree.h>
#include <gtest/gtest.h>

#include <cantor/type/type.h>
#include <cantor/type/type_kind.h>

int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}



namespace  cantor {

    void assert_value(const turbo::Result<uint32_t> &rs, uint32_t value) {
        ASSERT_TRUE(rs.ok())<<rs.status();
        ASSERT_EQ(rs.value_or_die(), value);
    }

    void assert_value(const EnumBuilder &builder, const std::string&name, uint32_t value) {
        auto rs = builder.find_value(name);
        ASSERT_TRUE(rs.ok())<<rs.status();
        ASSERT_EQ(rs.value_or_die(), value);
    }

    TEST(type, create) {
        /// BOOLEAN
        {
            auto ptr = BOOLEAN();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 1);
            ASSERT_EQ(ptr->serialize_size(), 1);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            auto ptr1 = BOOLEAN();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }

        /// INT8
        {
            auto ptr = INT8();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 1);
            ASSERT_EQ(ptr->serialize_size(), 1);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = INT8();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }

        /// INT16
        {
            auto ptr = INT16();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 2);
            ASSERT_EQ(ptr->serialize_size(), 2);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = INT16();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }

        /// INT32
        {
            auto ptr = INT32();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 4);
            ASSERT_EQ(ptr->serialize_size(), 4);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = INT32();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// INT32
        {
            auto ptr = INT32();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 4);
            ASSERT_EQ(ptr->serialize_size(), 4);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = INT32();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// INT64
        {
            auto ptr = INT64();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 8);
            ASSERT_EQ(ptr->serialize_size(), 8);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = INT64();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }

        /// INT128
        {
            auto ptr = INT128();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 16);
            ASSERT_EQ(ptr->serialize_size(), 16);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = INT128();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// UINT8
        {
            auto ptr = UINT8();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 1);
            ASSERT_EQ(ptr->serialize_size(), 1);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = UINT8();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// UINT16
        {
            auto ptr = UINT16();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 2);
            ASSERT_EQ(ptr->serialize_size(), 2);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = UINT16();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// UINT32
        {
            auto ptr = UINT32();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 4);
            ASSERT_EQ(ptr->serialize_size(), 4);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = UINT32();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// UINT64
        {
            auto ptr = UINT64();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 8);
            ASSERT_EQ(ptr->serialize_size(), 8);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = UINT64();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// UINT128
        {
            auto ptr = UINT128();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 16);
            ASSERT_EQ(ptr->serialize_size(), 16);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, true);
            auto ptr1 = UINT128();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        ///////////////////////////////////////////////////////////////////////////////////////////
        /// float
        /// FP8
        {
            auto ptr = FP8();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 1);
            ASSERT_EQ(ptr->serialize_size(), 1);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, true);
            auto ptr1 = FP8();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// FP16
        {
            auto ptr = FP16();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 2);
            ASSERT_EQ(ptr->serialize_size(), 2);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, true);
            auto ptr1 = FP16();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// FP32
        {
            auto ptr = FP32();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 4);
            ASSERT_EQ(ptr->serialize_size(), 4);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, true);
            auto ptr1 = FP32();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }
        /// FP64
        {
            auto ptr = FP64();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(true, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 8);
            ASSERT_EQ(ptr->serialize_size(), 8);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, true);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, true);
            auto ptr1 = FP64();
            ASSERT_EQ(true, ptr1->equals(*ptr));
        }

        /// STRING
        {
            auto ptr = STRING();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(std::string_view)
            ASSERT_EQ(ptr->serialize_size(), 32);  // sizeof(std::string)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false);
            ASSERT_EQ(ptr->is_fixed_width(), false);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = STRING(20);
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr2 = STRING(32);
            ASSERT_EQ(false, ptr1->equals(*ptr2));
        }

        /// FIXED_STRING
        {
            auto ptr = FIXED_STRING(20);
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(std::string_view)
            ASSERT_EQ(ptr->serialize_size(), 32);  // sizeof(std::string)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false);
            ASSERT_EQ(ptr->is_fixed_width(), false);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = FIXED_STRING(20);
            ASSERT_EQ(true, ptr1->equals(*ptr));
            auto ptr2 = FIXED_STRING(10);
            ASSERT_EQ(false, ptr1->equals(*ptr2));
        }

        /// BINARY
        {
            auto ptr = BINARY();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(std::string_view)
            ASSERT_EQ(ptr->serialize_size(), 32);  // sizeof(std::string)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false);
            ASSERT_EQ(ptr->is_fixed_width(), false);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = BINARY(20);
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr2 = BINARY(32);
            ASSERT_EQ(false, ptr1->equals(*ptr2));
        }

        /// FIXED_BINARY
        {
            auto ptr = FIXED_BINARY(20);
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(std::string_view)
            ASSERT_EQ(ptr->serialize_size(), 32);  // sizeof(std::string)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false);
            ASSERT_EQ(ptr->is_fixed_width(), false);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = FIXED_BINARY(20);
            ASSERT_EQ(true, ptr1->equals(*ptr));
            auto ptr2 = FIXED_BINARY(10);
            ASSERT_EQ(false, ptr1->equals(*ptr2));
        }

        /// TIMESTAMP
        {
            auto rs  = TIMESTAMP(pb::TimePrecision::TSP_MICRO);
            ASSERT_TRUE(rs.ok());
            auto ptr = rs.value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 12); // sizeof(turbo::Time)
            ASSERT_EQ(ptr->serialize_size(), 8);  // sizeof(int64)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(),true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto rs1 = TIMESTAMP(pb::TimePrecision::TSP_NANO);
            ASSERT_TRUE(rs1.ok());
            auto ptr1 = rs1.value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr2 = TIMESTAMP(pb::TimePrecision::TSP_MILLI).value_or_die();
            auto ptr3 = TIMESTAMP(pb::TimePrecision::TSP_SECONDS).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr2));
            auto micro = MICRO_TIMESTAMP();
            ASSERT_EQ(true, ptr->equals(*micro));
            auto nano = NANO_TIMESTAMP();
            ASSERT_EQ(true, ptr1->equals(*nano));
            auto milli = MILLI_TIMESTAMP();
            ASSERT_EQ(true, ptr2->equals(*milli));

            auto sec = SECOND_TIMESTAMP();
            ASSERT_EQ(true, ptr3->equals(*sec));
            auto nano_utc = NANO_TIMESTAMP("utc");
            auto nano_utc1 = NANO_TIMESTAMP("utc");
            ASSERT_EQ(false, ptr1->equals(*nano_utc));
            ASSERT_EQ(true, nano_utc1->equals(*nano_utc));
            auto nano_local = NANO_TIMESTAMP("local");
            ASSERT_EQ(true, ptr1->equals(*nano_local));
        }

        /// DURATION
        {
            auto ptr = DURATION(pb::TimePrecision::TSP_MICRO).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 12); // sizeof(turbo::Time)
            ASSERT_EQ(ptr->serialize_size(), 8);  // sizeof(int64)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(),true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = DURATION(pb::TimePrecision::TSP_NANO).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr2 = DURATION(pb::TimePrecision::TSP_MILLI).value_or_die();
            auto ptr3 = DURATION(pb::TimePrecision::TSP_SECONDS).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr2));
            auto micro = MICRO_DURATION();
            ASSERT_EQ(true, ptr->equals(*micro));
            auto nano = NANO_DURATION();
            ASSERT_EQ(true, ptr1->equals(*nano));
            auto milli = MILLI_DURATION();
            ASSERT_EQ(true, ptr2->equals(*milli));

            auto sec = SECOND_DURATION();
            ASSERT_EQ(true, ptr3->equals(*sec));
            auto nano_utc = NANO_DURATION();
            ASSERT_EQ(true, ptr1->equals(*nano_utc));
        }

        /// DECIMAL
        {
            auto ptr = DECIMAL64(18, 5).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 8);
            ASSERT_EQ(ptr->serialize_size(), 8);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = DECIMAL64(18, 5).value_or_die();
            ASSERT_EQ(true, ptr1->equals(*ptr));
            auto ptr2 = DECIMAL64(18, 6).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr2));
            /// precision excced
            auto rs = DECIMAL64(19, 5);
            ASSERT_FALSE(rs.ok());
            rs = DECIMAL64(17, 18);
            ASSERT_FALSE(rs.ok());
            rs = DECIMAL64(0, 0);
            ASSERT_FALSE(rs.ok());
        }
        /// ARRAY
        {

            auto ptr_int = INT8();
            auto ptr_rs = ARRAY(ptr_int, {10});
            ASSERT_TRUE(ptr_rs.ok());
            auto ptr = std::move(ptr_rs).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->serialize_size(), 16);  // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true); // array is fixed and child->is_fixed_width
            ASSERT_EQ(ptr->is_fixed_width(), true); // array is fixed and type is child->is_fixed_width
            ASSERT_EQ(ptr->is_primitive_type, false);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = ARRAY(ptr_int, {20}).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr2 = ARRAY(ptr_int, {10}).value_or_die();
            ASSERT_EQ(true, ptr->equals(*ptr2));
            std::cout << ptr->full_name << std::endl;
            auto ptrs = ARRAY(ptr_int, {10, 20}).value_or_die();
            std::cout << ptrs->full_name << std::endl;
            ptrs = ARRAY(ptr_int, {10, 20, -1}).value_or_die();
            std::cout << ptrs->full_name << std::endl;
        }
        /// MAP
        {

            auto ptr_key = INT64();
            auto ptr_value = INT8();
            ASSERT_EQ(ptr_key->is_orderable, true);
            auto ptr_rs = MAP(ptr_key, ptr_value);
            ASSERT_TRUE(ptr_rs.ok());
            auto ptr = std::move(ptr_rs).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 48); // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->serialize_size(), 16);  // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false); // array is fixed and child->is_fixed_width
            ASSERT_EQ(ptr->is_fixed_width(), false); // array is fixed and type is child->is_fixed_width
            ASSERT_EQ(ptr->is_primitive_type, false);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr_key1 = INT32();
            auto ptr_value1 = INT8();
            auto ptr1 = MAP(ptr_key1, ptr_value1).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr_key2 = INT64();
            auto ptr_value2 = INT8();
            auto ptr2 = MAP(ptr_key2, ptr_value2).value_or_die();
            ASSERT_EQ(true, ptr->equals(*ptr2));
            std::cout << ptr->full_name << std::endl;
        }

        /// SET
        {

            auto ptr_key = INT64();
            ASSERT_EQ(ptr_key->is_orderable, true);
            auto ptr_rs = SET(ptr_key);
            ASSERT_TRUE(ptr_rs.ok());
            auto ptr = std::move(ptr_rs).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 48); // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->serialize_size(), 16);  // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false); // array is fixed and child->is_fixed_width
            ASSERT_EQ(ptr->is_fixed_width(), false); // array is fixed and type is child->is_fixed_width
            ASSERT_EQ(ptr->is_primitive_type, false);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr_key1 = INT32();
            auto ptr1 = SET(ptr_key1).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr_key2 = INT64();
            auto ptr2 = SET(ptr_key2).value_or_die();
            ASSERT_EQ(true, ptr->equals(*ptr2));
            std::cout << ptr->full_name << std::endl;
        }

        /// STRUCT
        {

            auto ptr_mis = STRUCT({"a", "b"}, {INT64(), STRING(), INT8()});
            ASSERT_FALSE(ptr_mis.ok());
            ptr_mis = STRUCT({}, {});
            ASSERT_FALSE(ptr_mis.ok());
            ptr_mis = STRUCT({"a", "b", "c"}, {INT64(), STRING()});
            ASSERT_FALSE(ptr_mis.ok());
            ptr_mis = STRUCT({"a", "a", "c"}, {INT64(), STRING()});
            ASSERT_FALSE(ptr_mis.ok());
            auto ptr_rs = STRUCT({"a", "b", "c"}, {INT64(), STRING(), INT8()});
            ASSERT_TRUE(ptr_rs.ok());
            auto ptr = std::move(ptr_rs).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->serialize_size(), 16);  // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false); // array is fixed and child->is_fixed_width
            ASSERT_EQ(ptr->is_fixed_width(), false); // array is fixed and type is child->is_fixed_width
            ASSERT_EQ(ptr->is_primitive_type, false);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr_key1 = INT32();
            auto ptr1 = STRUCT({"a", "b", "c"}, {INT64(), STRING(), INT32()}).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr_key2 = INT64();
            auto ptr2 =  STRUCT({"a", "b", "c"}, {INT64(), STRING(), INT8()}).value_or_die();
            ASSERT_EQ(true, ptr->equals(*ptr2));
            std::cout << ptr->full_name << std::endl;
        }

        /// TUPLE
        {

            auto ptr_mis = TUPLE({});
            ASSERT_FALSE(ptr_mis.ok());
            auto ptr_rs = TUPLE({INT64(), STRING(), INT8()});
            ASSERT_TRUE(ptr_rs.ok());
            auto ptr = std::move(ptr_rs).value_or_die();
            ASSERT_NE(nullptr, ptr);

            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->serialize_size(), 16);  // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false); // array is fixed and child->is_fixed_width
            ASSERT_EQ(ptr->is_fixed_width(), false); // array is fixed and type is child->is_fixed_width
            ASSERT_EQ(ptr->is_primitive_type, false);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr1 = TUPLE({INT64(), STRING(), INT32()}).value_or_die();
            std::cout << "11111"<< std::endl;
            ASSERT_EQ(false, ptr1->equals(*ptr));

            auto ptr2 =  TUPLE({INT64(), STRING(), INT8()}).value_or_die();
            ASSERT_EQ(true, ptr->equals(*ptr2));
            std::cout << ptr->full_name << std::endl;
        }
        /// UNION
        {

            auto ptr_mis = UNION({"a", "b"}, {INT64(), STRING(), INT8()});
            ASSERT_FALSE(ptr_mis.ok());
            ptr_mis = UNION({}, {});
            ASSERT_FALSE(ptr_mis.ok());
            ptr_mis = UNION({"a", "b", "c"}, {INT64(), STRING()});
            ASSERT_FALSE(ptr_mis.ok());
            auto ptr_rs = UNION({"a", "b", "c"}, {INT64(), STRING(), INT8()});
            ASSERT_TRUE(ptr_rs.ok());
            auto ptr = std::move(ptr_rs).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(ptr->runtime_size(), 16); // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->serialize_size(), 16);  // sizeof(turbo::span<uint8_t>)
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false); // array is fixed and child->is_fixed_width
            ASSERT_EQ(ptr->is_fixed_width(), false); // array is fixed and type is child->is_fixed_width
            ASSERT_EQ(ptr->is_primitive_type, false);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            auto ptr_key1 = INT32();
            auto ptr1 = UNION({"a", "b", "c"}, {INT64(), STRING(), INT32()}).value_or_die();
            ASSERT_EQ(false, ptr1->equals(*ptr));
            auto ptr_key2 = INT64();
            auto ptr2 =  UNION({"a", "b", "c"}, {INT64(), STRING(), INT8()}).value_or_die();
            ASSERT_EQ(true, ptr->equals(*ptr2));
            std::cout << ptr->full_name << std::endl;
        }

    }
    /// ENUM BUILDER
    TEST(type, enum_builder) {
        {
            EnumBuilder builder = EnumBuilder();
            builder.set_uri("ns.db.filetype");
            builder.allow_alias(false);
            auto rs = builder.emplace("txt");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("doc");
            ASSERT_TRUE(rs.ok())<<rs;
            std::cout<<builder.to_string()<<std::endl;
            rs = builder.emplace("txt");
            ASSERT_FALSE(rs.ok())<<rs;
        }
        {
            EnumBuilder builder = EnumBuilder();
            builder.set_uri("ns.db.filetype");
            builder.allow_alias(false);
            auto rs = builder.emplace("txt");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("doc");
            ASSERT_TRUE(rs.ok())<<rs;
            std::cout<<builder.to_string()<<std::endl;
            rs = builder.emplace("text", 0);
            ASSERT_FALSE(rs.ok())<<rs;
        }
        {
            EnumBuilder builder = EnumBuilder();
            builder.set_uri("ns.db.filetype");
            builder.allow_alias(true);
            auto rs = builder.emplace("txt");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("doc", 10);
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("docx");
            assert_value(builder, "docx", 11);
            ASSERT_TRUE(rs.ok())<<rs;
            assert_value(builder, "docx", 11);
            rs = builder.emplace("el");
            ASSERT_TRUE(rs.ok())<<rs;
            assert_value(builder, "el", 12);
            rs = builder.emplace("ppt", 5);
            ASSERT_TRUE(rs.ok())<<rs;
            assert_value(builder, "ppt", 5);
            rs = builder.emplace("pptx");
            ASSERT_TRUE(rs.ok())<<rs;
            assert_value(builder, "pptx", 6);
            rs = builder.emplace("tx", 6);
            ASSERT_TRUE(rs.ok())<<rs;
            std::cout<<builder.to_string()<<std::endl;
        }
        {
            EnumBuilder builder = EnumBuilder();
            builder.set_uri("ns.db.filetype");
            builder.allow_alias(true);
            auto rs = builder.emplace("txt");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("doc");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("docx", 1);
            ASSERT_TRUE(rs.ok())<<rs;
            std::cout<<builder.to_string()<<std::endl;
        }

        {
            EnumBuilder builder = EnumBuilder();
            builder.set_uri("ns.db.compress_type");
            builder.allow_alias(true);
            auto rs = builder.emplace("zlib");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("zstd");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("lz4", 10);
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("lzma");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder.emplace("snappy", 1);
            ASSERT_TRUE(rs.ok())<<rs;
            std::cout<<builder.to_string()<<std::endl;
            auto ed = std::move(builder).build();
            auto emrs = ENUM(ed);
            ASSERT_TRUE(emrs.ok())<<emrs;
            auto ptr = emrs.value_or_die();
            ASSERT_NE(ptr, nullptr);
            ASSERT_EQ(ptr->runtime_size(), 4);
            ASSERT_EQ(ptr->serialize_size(), 4);
            ASSERT_EQ(ptr->is_orderable, true);
            ASSERT_EQ(ptr->is_comparable, true);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), true);
            ASSERT_EQ(ptr->is_fixed_width(), true);
            ASSERT_EQ(ptr->is_primitive_type, true);
            ASSERT_EQ(ptr->is_numeric_type, false);
            ASSERT_EQ(ptr->is_integer_type, false);
            ASSERT_EQ(ptr->is_float_type, false);
            EnumBuilder builder1 = EnumBuilder();
            builder1.set_uri("ns.db.compress_type");
            builder1.allow_alias(true);
            rs = builder1.emplace("zlib");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder1.emplace("zstd");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder1.emplace("lz4", 9);
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder1.emplace("lzma");
            ASSERT_TRUE(rs.ok())<<rs;
            rs = builder1.emplace("snappy", 1);
            ASSERT_TRUE(rs.ok())<<rs;
            std::cout<<builder1.to_string()<<std::endl;
            auto ed1 = std::move(builder1).build();
            auto emrs1 = ENUM(ed1);
            ASSERT_TRUE(emrs1.ok())<<emrs1;
            auto ptr1 = std::move(emrs1).value_or_die();
            std::cout<<"ptr1: "<<ptr1->full_name<<std::endl;
            ASSERT_EQ(ptr1->equals(*ptr), false);

        }
    }
    TEST(type, create_udf) {
        /// PROTO
        {
            auto frs = PROTO("");
            ASSERT_FALSE(frs.ok());
            auto rs = PROTO("a.b.c");
            ASSERT_TRUE(rs.ok());
            auto ptr =std::move(rs).value_or_die();
            ASSERT_NE(nullptr, ptr);
            ASSERT_EQ(false, ptr->is_fixed_width());
            ASSERT_EQ(ptr->runtime_size(), 16);
            ASSERT_EQ(ptr->serialize_size(), 32);
            ASSERT_EQ(ptr->is_orderable, false);
            ASSERT_EQ(ptr->is_comparable, false);
            ASSERT_EQ(ptr->is_fixed_serialize_width(), false);
            ASSERT_EQ(ptr->is_fixed_width(), false);
            ASSERT_EQ(ptr->is_primitive_type, false);
            auto ptr1 = PROTO("a.b.c").value_or_die();
            ASSERT_EQ(true, ptr1->equals(*ptr));
            auto ptr2 = PROTO("a.b.c.d").value_or_die();
            ASSERT_EQ(false, ptr2->equals(*ptr));
            ASSERT_EQ(true, ptr2->kind_equals(ptr));
        }
    }
}  // namespace  cantor

